//
// UART
//


#include "gpio.h"
#include "asm_tools.h"


//
// Registres UART
#define UART_DR		0x20201000u	// Data register
#define UART_RSRECR	0x20201004u
#define UART_FR		0x20201018u	// Flag register
#define UART_IBRD	0x20201024u	// Integer Daud rate divisor
#define UART_FBRD	0x20201028u	// Fractional Baud rate divisor
#define UART_LCRH	0x2020102Cu	// Line control register
#define UART_CR 	0x20201030u	// Control register
#define UART_IFLS	0x20201034u	// Interupt FIFO level select register
#define UART_IMSC	0x20201038u	// Interupt mask set clear register
#define UART_RIS	0x2020103Cu	// Raw Interupt Status register
#define UART_MIS	0x20201040u	// Masked Interupt Status Register
#define UART_ICR	0x20201044u	// Interupt clear register
#define UART_ITCR	0x20201080u	// Test Control register
#define UART_ITIP	0x20201084u	// Integration test input reg
#define UART_ITOP	0x20201088u	// Integration test output reg
#define UART_TDR	0x2020108Cu	// Test data reg
// Constantes GPIO utiles aux UART
#define UART_TXD0_PIN	14u	// UART TDX0 pin sur ALT0
#define UART_RDX0_PIN	15u // UART RDX0 pin sur ALT0
#define GPIO_ALT0		4u	// GPIO fonction ALT0
#define GPIO_TDX0_OFF	((14u % 10u) * 3u)
#define GPIO_RDX0_OFF	((15u % 10u) * 3u)


//
// Initialisation
void uart_init(void)
{
	// On désactive UART
	set32(UART_CR, 0u);

	// Initialisation GPIO (14 et 15)
	// On règle la fonction sur ALT0 pour les bons pins
	set32(GPIO_FSEL1, get32(GPIO_FSEL1) | (GPIO_ALT0 << GPIO_TDX0_OFF));
	set32(GPIO_FSEL1, get32(GPIO_FSEL1) | (GPIO_ALT0 << GPIO_RDX0_OFF));
	// On règle le pull down
	set32(GPIO_PUD, 0u);
	delay(150u);
	set32(GPIO_PUDCLK0, (1u << UART_TXD0_PIN) | (1u << UART_RDX0_PIN));
	delay(150u);
	set32(GPIO_PUD, 0u);
	set32(GPIO_PUDCLK0, 0u);

	// On initialisation UART
	// On clear la line
	set32(UART_LCRH, 0u);
	// On clear les intéruptions
	set32(UART_ICR, 0u);
	// On règles le baud rate à 115200 baud
	set32(UART_IBRD, 1u);
	set32(UART_FBRD, 40u);
	// Line control :
	// - break disable
	// - parity disable
	// - stop bits disable
	// - fifo enable
	// - word length = 8 bits
	set32(UART_LCRH, (1u << 4u) | (3u << 5u));
	// Seuil FIFO
	// - On utilise pas la transmit fifo
	// - receive fifo à 1/2
	set32(UART_IFLS, 0u);
	// Interruption
	// - On active les interruptions de la receive FIFO et les erreurs
	set32(UART_IMSC, (1u << 1u) | (1u << 4u) | (1u << 5u)
						| (1u << 6u) | (1u << 7u) | (1u << 8u)
						| (1u << 9u) | (1u << 10u));
	// Controle :
	// - on active l'UART
	// - pas de loopback
	// - activation de la réception/émission
	// - pas de RTS
	// - pas de flowcontrol
	set32(UART_CR, (1u << 0u) | (1u << 8u) | (1u << 9u));
}

//
// Permet d'envoyer des charactères
int uart_send(const char *data)
{
	do
	{
		// On attend que l'UART soit disponible (on n'utilise pas la FIFO)
		while ((get32(UART_FR) & (1u << 5u)) != 0u);
		// On écrit la données
		set32(UART_DR, (unsigned int)*(data++));

	} while (*data != '\0');

	return 0;
}

//
// Permet de savoir si la receive fifo est vide
int uart_is_receive_fifo_empty(void)
{
	if ((get32(UART_FR) & (1u << 4u)) != 0)
	{
		return 0;
	}

	return 1;
}

//
// Permet de lire un byte
// CONTRAT : on doit s'assurer que la receive fifo n'est pas vide
//	avant de l'appeler.
unsigned int uart_read_byte(void)
{
	return (get32(UART_DR) & 0xFFu);
}
